﻿using System;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Framework.Serialization;
using LFloatMath.Math;

namespace IQIGame.Onigao.GamePlay
{
    public enum ETAnyType
    {
        Min,
        Bool,
        Int32,
        Int64,
        LFloat,
        String,
        Vector2,
        Vector3,
        Max
    }

    public interface TAny
    {
        void Serialize(SOutputStream _buf);
        void DeSerialize(SInputStream _buf);
        void Free();
    }

    public class TAnyVal<T> : TAny, IReusableClassWithFree
    {
        public T value { get; set; }

        public TAnyVal(T v)
        {
            value = v;
        }

        public TAnyVal()
        {
        }

        public virtual void Serialize(SOutputStream _buf)
        {
        }

        public virtual void DeSerialize(SInputStream _buf)
        {
        }

        public virtual void Free()
        {
            ClassPool.Put(this);
        }
        
        public uint MaxStore => 10;
        public void OnReset()
        {
            this.value = default;
        }

#if UNITY_EDITOR
        public override string ToString()
        {
            return this.value.ToString();
        }
#endif
    }

    public sealed class TAnyBool : TAnyVal<bool>
    {
        public TAnyBool(bool v) : base(v)
        {
        }

        public TAnyBool()
        {
        }
        
        public override void Serialize(SOutputStream _buf)
        {
            base.Serialize(_buf);
            _buf.Write_boolean(this.value);
        }

        public override void DeSerialize(SInputStream _buf)
        {
            base.DeSerialize(_buf);
            this.value = _buf.Read_boolean();
        }

        public override void Free()
        {
            ClassPool.Put(this);
        }
    }

    public sealed class TAnyInt32 : TAnyVal<Int32>
    {
        public TAnyInt32(Int32 v) : base(v)
        {
        }

        public TAnyInt32()
        {
        }

        public override void Serialize(SOutputStream _buf)
        {
            base.Serialize(_buf);
            _buf.Write_int(this.value);
        }

        public override void DeSerialize(SInputStream _buf)
        {
            base.DeSerialize(_buf);
            this.value = _buf.Read_int();
        }

        public override void Free()
        {
            ClassPool.Put(this);
        }
    }

    public sealed class TAnyInt64 : TAnyVal<Int64>
    {
        public TAnyInt64(Int64 v) : base(v)
        {
        }

        public TAnyInt64()
        {
        }

        public override void Serialize(SOutputStream _buf)
        {
            base.Serialize(_buf);
            _buf.Write_long(this.value);
        }

        public override void DeSerialize(SInputStream _buf)
        {
            base.DeSerialize(_buf);
            this.value = _buf.Read_long();
        }

        public override void Free()
        {
            ClassPool.Put(this);
        }
    }

    public sealed class TAnyLFloat : TAnyVal<LFloat>
    {
        public TAnyLFloat(LFloat v) : base(v)
        {
        }

        public TAnyLFloat()
        {
        }

        public override void Serialize(SOutputStream _buf)
        {
            base.Serialize(_buf);
            _buf.Write_long(this.value._val);
        }

        public override void DeSerialize(SInputStream _buf)
        {
            base.DeSerialize(_buf);
            this.value = new LFloat(true, _buf.Read_long());
        }

        public override void Free()
        {
            ClassPool.Put(this);
        }
    }

    public sealed class TAnyString : TAnyVal<string>
    {
        public TAnyString(string v) : base(v)
        {
        }

        public TAnyString()
        {
        }

        public override void Serialize(SOutputStream _buf)
        {
            base.Serialize(_buf);
            _buf.Write_string(this.value);
        }

        public override void DeSerialize(SInputStream _buf)
        {
            base.DeSerialize(_buf);
            this.value = _buf.Read_string();
        }

        public override void Free()
        {
            ClassPool.Put(this);
        }
    }

    public sealed class TAnyVector2 : TAnyVal<LVector2>
    {
        public TAnyVector2(LVector2 v) : base(v)
        {
        }

        public TAnyVector2()
        {
        }

        public override void Serialize(SOutputStream _buf)
        {
            base.Serialize(_buf);
            _buf.Write_long(this.value._x);
            _buf.Write_long(this.value._y);
        }

        public override void DeSerialize(SInputStream _buf)
        {
            base.DeSerialize(_buf);
            this.value = new LVector2(
                new LFloat(true, _buf.Read_long()),
                new LFloat(true, _buf.Read_long()));
        }

        public override void Free()
        {
            ClassPool.Put(this);
        }
    }

    public sealed class TAnyVector3 : TAnyVal<LVector3>
    {
        public TAnyVector3(LVector3 v) : base(v)
        {
        }

        public TAnyVector3()
        {
        }

        public override void Serialize(SOutputStream _buf)
        {
            base.Serialize(_buf);
            _buf.Write_long(this.value._x);
            _buf.Write_long(this.value._y);
            _buf.Write_long(this.value._z);
        }

        public override void DeSerialize(SInputStream _buf)
        {
            base.DeSerialize(_buf);
            this.value = new LVector3(
                new LFloat(true, _buf.Read_long()),
                new LFloat(true, _buf.Read_long()),
                new LFloat(true, _buf.Read_long()));
        }

        public override void Free()
        {
            ClassPool.Put(this);
        }
    }

    public static class TAnyHelper
    {
        public static void SetAny<T>(TAny obj, T v)
        {
            if (obj is null) return;
            TAnyVal<T> t = obj as TAnyVal<T>;
            t.value = v;
        }

        public static T GetAny<T>(TAny obj, T defaultValue = default(T))
        {
            if (obj == null)
            {
                return defaultValue;
            }

            TAnyVal<T> t = obj as TAnyVal<T>;
            if (t == null)
            {
                return defaultValue;
            }

            return t.value;
        }

        public static TAny NewAny(ETAnyType type)
        {
            TAny obj = null;
            switch (type)
            {
                case ETAnyType.Bool:
                    obj = ClassPool.Get<TAnyBool>();
                    break;
                case ETAnyType.Int32:
                    obj = ClassPool.Get<TAnyInt32>();
                    break;
                case ETAnyType.Int64:
                    obj = ClassPool.Get<TAnyInt64>();
                    break;
                case ETAnyType.LFloat:
                    obj = ClassPool.Get<TAnyLFloat>();
                    break;
                case ETAnyType.String:
                    obj = ClassPool.Get<TAnyString>();
                    break;
                case ETAnyType.Vector2:
                    obj = ClassPool.Get<TAnyVector2>();
                    break;
                case ETAnyType.Vector3:
                    obj = ClassPool.Get<TAnyVector3>();
                    break;
            }

            return obj;
        }
    }
}